package main

import (
	"flag"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/jacobsa/go-serial/serial"
	"io"
	"log"
	"modbus-go-demo/app"
	"modbus-go-demo/utils/tools"
	"time"
)

/*
串口端 RS485,RS432,RS422
*/

var Port io.WriteCloser
var portName, httpPort *string
var rate, dataBits, stopBits, minimumReadSize *int

func init() {
	portName = flag.String("port", "COM4", "串口名(端口)")
	rate = flag.Int("rate", 9600, "波特率")
	dataBits = flag.Int("data_bits", 8, "数据位")
	stopBits = flag.Int("stop_bits", 1, "停止位")
	minimumReadSize = flag.Int("min_read_size", 4, "每次读取操作的最小字节数")
	httpPort = flag.String("http_port", "9988", "http服务端口")
	flag.Parse()
}

func main() {
	options := serial.OpenOptions{
		PortName:        *portName,
		BaudRate:        uint(*rate),
		DataBits:        uint(*dataBits),
		StopBits:        uint(*stopBits),
		MinimumReadSize: uint(*minimumReadSize),
	}

	port, err := serial.Open(options)
	if err != nil {
		fmt.Println("打开串口失败", err.Error())
		return
	}
	defer port.Close()
	fmt.Printf("【%s】%s\n", "打开串口成功", *portName)
	Port = port

	go httpSever()
	//go writeData()

	// 无限循环读取数据
	for {
		buffer := make([]byte, 4096) // 缓冲区大小
		n2, err2 := port.Read(buffer)
		if err2 != nil {
			fmt.Printf("读取错误: %s\n", err2.Error())
			continue
		}
		// 输出读到的数据
		if n2 > 0 {
			recvData := tools.ByteArrayToHexStr(buffer[:n2])
			fmt.Printf("【%s】len=%d : %s\n", tools.GetNow(), n2, recvData)
			if n2 != 8 {
				fmt.Printf("warning ??? 未知的数据包\n")
				continue
			}
			addr := buffer[0:1]
			funCode := buffer[1:2]
			//startAddr := buffer[2:4]
			addrNum := buffer[4:6]
			//crc := buffer[6:8]

			if funCode[0] == 0x03 {
				n := tools.BytesToUint16(addrNum, "big")
				resp := make([]byte, 0)
				resp = append(resp, addr...)
				resp = append(resp, funCode...)
				resp = append(resp, byte(2*n))
				for i := 1; i <= int(2*n); i++ {
					resp = append(resp, 0x08)
				}
				resp = app.AppendCrc16(resp)
				_, err2 = port.Write(resp)
				if err2 != nil {
					fmt.Printf("Write error %s\n", err2.Error())
				} else {
					fmt.Printf("Write success %s\n", tools.ByteArrayToHexStr(resp))
				}
			} else if funCode[0] == 0x06 {
				fmt.Printf("todo 写入功能逻辑处理\n")
			} else {
				fmt.Printf("warning ??? 未知的功能码\n")
				continue
			}

		}
		// 可以适当休息一下，避免CPU占用过高
		time.Sleep(5 * time.Millisecond)
	}
}

func httpSever() {
	appPort := *httpPort
	var r *gin.Engine
	gin.SetMode(gin.ReleaseMode)
	// 设置全局日志中间件
	r = gin.New()
	r.Any("/api/client_push", func(ctx *gin.Context) {
		data := ctx.Query("data")
		b, err := tools.HexStrToByteArray(data)
		if err != nil {
			ctx.JSON(200, gin.H{
				"code": 0,
				"msg":  "参数无效",
				"data": err.Error(),
			})
			return
		}
		if len(b) != 86 {
			ctx.JSON(200, gin.H{
				"code": 0,
				"msg":  "参数无效,长度不对",
				"data": "",
			})
			return
		}
		// 向串口写入数据
		_, err = Port.Write(b)
		if err != nil {
			ctx.JSON(200, gin.H{
				"code": 0,
				"msg":  "串口写入数据失败",
				"data": err.Error(),
			})
			return
		}
		fmt.Printf("success write %d bytes\n", len(data))
		ctx.JSON(200, gin.H{
			"code": 0,
			"msg":  "success",
			"data": data,
		})
	})

	fmt.Printf("%-32s%-32s\n", "http listen on "+appPort, "OK")
	err := r.Run(":" + appPort)
	if err != nil {
		log.Fatal(err.Error())
	}
}
